package controllers;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Query;

import org.apache.commons.mail.EmailException;

import models.Email;
import models.Entities;
import models.Log;
import models.Organization;
import models.Permission;
import models.UnRegisteredEmail;
import models.User;
import play.db.jpa.GenericModel.JPAQuery;
import play.db.jpa.JPA;
import play.mvc.Controller;
import java.util.Random;

public class Usercontroller extends Controller {

	/**
	 * It takes a message and show it in the views.. and this message is if a
	 * user entered a wrong attribute of logged out
	 * 
	 * @param message
	 *            A string that the index returns whenever i user does something
	 *            unexpected
	 * @author Nourhan El Sawa
	 */
	public static void index(String message) {

		render(message);
	}

	/**
	 * Shows user profile from session and differs from the page of login
	 * because user do not have to enter his email or password again he can just
	 * move through pages with his id(Session management)
	 * 
	 * @author Nourhan El Sawa
	 */

	public static void profile() {
		String id = session.get("userId");
		if (id == null) {
			Home.home(null, null, "Please Login");
		}
		long userId = Long.parseLong(id);
		User user = User.findById(userId);
		String email = "admin@admin.com";
		List<Log> allLog = Log.findAll();
		List<Log> userLog = new ArrayList<Log>();
		for (int i = allLog.size() - 1; i > 0; i--) {

			if (allLog.get(i).performer != null
					&& allLog.get(i).organization != null && userLog.size() < 5) {
				System.out.println(allLog.get(i).performer.id);
				System.out.println(user.id);

				if (allLog.get(i).performer == user) {

					userLog.add(allLog.get(i));

				}
			}
		}
		render(user, email, userLog);
	}

	/**
	 * takes the user mail and password and direct the user to his profile but
	 * if he entered a wrong email or password he will be redirected to the page
	 * to insert his info again.
	 * 
	 * @param myMail
	 *            A string that indicates the user email(user.email).
	 * @param myPassword
	 *            A String that indicates the user password(user.password).
	 * @author Nourhan El Sawa
	 */
	public static void logIn(String myMail, String myPassword) {

		List<User> list = User.getUsers();
		list = User.find("email", myMail).fetch(1);
		if (list.size() == 1) {
			User user = User.find("byEmail", myMail).first();

			if (user.viewed == true) {
				if (myPassword.equals(user.password)) {
					String userId = user.id.toString();
					session.put("userId", userId);
					System.out.println(user.password);
					System.out.println(myPassword);
					System.out.println("Go to profile");
					profile();

					render(user);

				} else {

					Home.home("You entered a wrong password", null, null);
				}
			} else {

				Home.home("User is already deleted", null, null);
			}
		} else {

			Home.home("Enter a valid Email", null, null);
		}
	}

	/**
	 * The user will have in his view the ability to send an email to an
	 * unregistered user to join the community therefore this method take the id
	 * of user from session management and the mail of unregistered user and
	 * will check if this mail is not already in the database and if not an
	 * email will be sent to the unregistered user
	 * 
	 * @param userMail
	 *            A string that indicates the mail of the unregistered user that
	 *            the user wishes to invite to the community.
	 * 
	 * @author Nourhan El Sawa
	 */
	public static void inviteUnregistered(String userMail)
			throws EmailException {
		long id = Long.parseLong(session.get("userId"));
		User user = User.findById(id);
		String message;
		List<User> list = User.getUsers();
		list = User.find("email", userMail).fetch(1);

		if (list.size() == 0) {
			Email mail = new Email(
					user.email,
					userMail,
					"Invitation",
					"You are invited to join the community of "
							+ user.name
							+ " of email "
							+ user.email
							+ " if you accept visit our site and register http://localhost:9000/");

			message = (user.name
					+ " You have successfully sent an invitation to " + mail.destination);

			mail.sendEmail();
			render(message);
		} else {
			System.out.println("User is already registred");
			User user2 = User.find("byEmail", userMail).first();
			message = (user2.name + " already exist and  the user account is :" + userMail);
			render(message);

		}

	}

	/**
	 * Takes the parameters and always create a user with 0 counter as he is not
	 * in any community and have the viewed value of true and he can then edit
	 * in his profile later And if the user entered an email that already exist
	 * he will be directed to the home page and also a new Permission whenever a
	 * user Register
	 * 
	 * 
	 * @param myMail
	 *            A string that indicates the mail of the user that he will
	 *            register with
	 * @param myName
	 *            A string that indicates the name of the user that he will
	 *            register with
	 * @param myPassword
	 *            A string that indicates the password of the user that he will
	 *            register with
	 * @param confirmPass
	 *            A string that indicates the confirmed password to be sure that
	 *            the user knows and remember his password
	 * @param contributionPreference
	 *            A boolean that indicates weather the user would like
	 *            notification to be send to him or not in things he contributed
	 *            in.
	 * @param subscribePreference
	 *            A boolean that indicates weather the user would like
	 *            notification to be send to him or not in things he subscribed
	 *            in.
	 * @author Nourhan El Sawa
	 */
	public static void register(String myMail, String myName,
			String myPassword, String confirmPass,
			boolean contributionPreference, boolean subscribePreference) {

		List<User> list = User.getUsers();
		list = User.find("email", myMail).fetch(1);
		if (list.size() == 0) {
			User user = new User(myMail, myName, myPassword, 0, true,
					contributionPreference, subscribePreference);
			user.save();
			Permission newPermission = new Permission("ideaDeveloper", null,
					user, null);
			newPermission.save();
			Query query = JPA
					.em()
					.createQuery(
							"DELETE FROM User WHERE email=null AND name=null AND password=null ");
			query.executeUpdate();

			boolean comparison = UnRegisteredEmail.compareEmail(myMail);
			if (comparison == true) {

				UnRegisteredEmail email = UnRegisteredEmail.find("email",
						myMail).first();
				email.moveInivtations(user);
				email.delete();
			}

			session.put("userId", user.id);
			if (user.invitations.size() != 0) {
				Invitations.showInvitations();
			} else {
				profile();
			}
		}

		else {

			Home.home(null,
					"Email already exist..Try registering with another Email",
					null);
		}
	}

	/**
	 * a button on the profile that logs out a user and he should login again to
	 * enter his profile.
	 * 
	 * @Author Nourhan El Sawa
	 */
	public static void logout() {

		long id = Long.parseLong(session.get("userId"));
		User user = User.findById(id);
		session.remove("userId");
		System.out.println(user.id);
		Home.home(null, null, "You have logged out!");

	}

	/**
	 * gets the user that needs deletion from the session, deletes the User and
	 * displays a confirmation message on the login page.
	 * 
	 * @Author Malak El Kommos
	 */

	public static void deleteProfile() {
		long id = Long.parseLong(session.get("userId"));
		User user = User.findById(id);
		user.deleteUser();
		Home.home(null, null, "Your profile has been deleted");
	}

	/**
	 * takes the user that needs deletion by id, deletes the User and goes back
	 * to list of users.
	 * 
	 * @param userId
	 *            the user's id
	 * 
	 * @Author Malak El Kommos
	 */

	public static void deleteOthersProfile(long userId) {
		User user = User.findById(userId);
		user.deleteUser();
		showListOfAllUsers();
	}

	/**
	 * gets the user that needs edition by id, and returns it.
	 * 
	 * @param userId
	 *            the user's id
	 * 
	 * @Author Malak El Kommos
	 */

	public static void editOthersProfile(long userId) {
		User user = User.findById(userId);
		render(user);
	}

	/**
	 * gets the user that needs edition by id, updates his info, save in the
	 * data base and goes back to list of users.
	 * 
	 * @param userId
	 *            the user's id
	 * 
	 * @Author Malak El Kommos
	 */

	public static void otherUserEdited(Long userId) {

		User user = User.findById(userId);

		user.name = params.get("myName");
		user.email = params.get("myMail");

		boolean contribution = Boolean.parseBoolean(params.get("contribution"));
		user.contribution_preference = contribution;

		boolean subscription = Boolean.parseBoolean(params.get("subscription"));
		user.subscribe_preference = subscription;

		user.save();
		showListOfAllUsers();

	}

	/**
	 * gets the list of all the users in the system
	 * 
	 * @Author Malak El Kommos
	 */

	public static void showListOfAllUsers() {
		Long id = Long.parseLong(session.get("userId"));
		User user = User.findById(id);
		List<User> usersList = User.findAll();

		for (int i = 0; i < usersList.size(); i++) {

			if (usersList.get(i).name.equals("Anonymous"))
				usersList.remove(i);

		}
		for (int i = 0; i < usersList.size(); i++) {
			if (usersList.get(i).email.equals("admin@admin.com"))
				usersList.remove(i);

		}

		render(usersList, user);
	}

	/**
	 * a method that the view calls that return the edit page and in it the info
	 * of the user using the session
	 * 
	 * @Author Nourhan Elsawa
	 */
	public static void edit() {
		long id = Long.parseLong(session.get("userId"));
		User user = User.findById(id);
		render(user);

	}

	/**
	 * a method that enables user to edit his profile immediately but the user
	 * cannot enter an email that is used by another user.
	 * 
	 * @param myName
	 *            A String that indicates the name of the user that he might
	 *            wishes to change.
	 * @param myMail
	 *            A string that indicates the mail of the user that he might
	 *            wishes to change.
	 * @param myPassword
	 *            A string that indicates the password of the user that he might
	 *            wishes to change.
	 * @param contributionPreference
	 *            A boolean that indicates the contribution preference of the
	 *            user that he might wishes to change.
	 * @param subscribePreference
	 *            A boolean that indicates the subscribe preference of the user
	 *            that he might wishes to change.
	 * @Author Nourhan Elsawa
	 */
	public static void userEdited(String myName, String myMail,
			String myPassword, boolean contributionPreference,
			boolean subscribePreference) {
		long id = Long.parseLong(session.get("userId"));
		User user = User.findById(id);
		user.name = myName;
		List<User> list = User.getUsers();
		list = User.find("email", myMail).fetch(1);
		if (list.size() == 0) {
			user.email = myMail;
		}
		user.password = myPassword;
		user.contribution_preference = contributionPreference;
		user.subscribe_preference = subscribePreference;
		user.save();
		profile();
	}

	public static void assign() {
		render();
	}

	/**
	 * Enables the admin to assign any user as an organization lead therefore
	 * this method takes user id and organization id and search if this user is
	 * already in the this organization(his permission will only be updates) or
	 * he is not a member in the organization(new permission will be added)
	 * 
	 * @param userId
	 *            A long that indicated the user.id
	 * @param organizationId
	 *            A long that indicated the organization.id
	 * 
	 *            added log statement inside the method to keep track of what
	 *            happened
	 * 
	 * 
	 * @author Nourhan El Sawa
	 * @author Mai Selwanes
	 */
	public static void assignOrganizationLead(long userId, long organizationId) {

		User user = User.findById(userId);
		Organization organization = Organization.findById(organizationId);
		long id = Long.parseLong(session.get("userId"));
		User admin = User.findById(id);
		String message = "You have successfully assigned user " + user.name
				+ " to org" + organization.name;
		System.out.println(organization.lead.name);
		if (organization.lead.name.equals(null)) {
			if (admin.userPermissionInOrganization(user.id, organization.id) != null) {
				Permission permission = admin.userPermissionInOrganization(
						user.id, organization.id);
				System.out.println(permission.aUserType
						+ "  before the if statement");
				if (permission.aUserType.equals("ideaDeveloper") == true
						|| permission.aUserType.equals("organizer") == true) {
					permission.aUserType = "organizationLead";
					permission.save();
					organization.lead = user;
					organization.save();
					System.out.println(organization.lead.name);
					System.out.println(permission.aUserType
							+ " in the if statement");

					ArrayList<User> receivers = new ArrayList<User>();
					receivers.add(user);
					admin.sendNotificationWithType(
							"you have becomed an organization lead in"
									+ organization.name, receivers,
							"Organization", organizationId);

					Log log = new Log(organization, user,
							" has been assigned as an Organization lead.");
					log.save();

				} else

				{
					if (permission.aUserType.equals("organizationLead")) {
						message = user.name
								+ " is already an organization lead in  "
								+ organization.name;
					}
				}
			} else {

				Permission newPermission = new Permission("organizationLead",
						organization, user, null);
				newPermission.save();
				organization.lead = user;
				organization.save();
				System.out.println(newPermission.aUserType
						+ "  in the else statement");
				user.organization.add(organization);
				user.save();

				ArrayList<User> receivers = new ArrayList<User>();
				receivers.add(user);
				admin.sendNotificationWithType(
						"you have becomed an organization lead in"
								+ organization.name, receivers, "Organization",
						organization.id);

			}

		} else
			message = organization.lead.name + " is already a lead for  "
					+ organization.name;

		render(message);
	}

	/**
	 * Enables the admin to assign any user as an organizer in any entity of any
	 * organization therefore this method takes user id ,organization id and
	 * entity id and search if this user is already in the this organization(his
	 * permission will only be updates) or he is not a member in the
	 * organization(new permission will be added)
	 * 
	 * @param userId
	 *            A long that indicated the user.id
	 * @param organizationId
	 *            A long that indicated the organization.id
	 * @param entityId
	 *            A long that indicated the entity.id
	 * 
	 * 
	 * 
	 * 
	 * @author Nourhan El Sawa
	 */

	public static void assignOrganizer(long userId, long organizationId,
			long entityId) {
		String message = "";
		Long id = Long.parseLong(session.get("userId"));
		User admin = User.findById(id);
		User user = User.findById(userId);
		Organization organization = Organization.findById(organizationId);
		Entities entity = Entities.findById(entityId);
		if (admin.userPermissionInOrganization(user.id, organization.id) != null
				|| admin.userPermissionInEntity(user.id, organization.id,
						entity.id) != null) {
			Permission permissionOrg = admin.userPermissionInOrganization(
					userId, organizationId);
			System.out.println(permissionOrg.aUserType
					+ " in org b4 the if statement controller ");
			Permission permissionEnt = admin.userPermissionInEntity(userId,
					organizationId, entityId);

			if (permissionOrg.aUserType.equals("ideaDeveloper")) {
				permissionOrg.aUserType = "organizer";
				permissionOrg.save();
				Permission permissionInEntity = new Permission("organizer",
						organization, user, entity);
				permissionInEntity.save();
				entity.entityOrganizers.add(user);
				entity.save();
				System.out.println("organizer is assigned");

				ArrayList<User> receivers = new ArrayList<User>();
				receivers.add(user);
				admin.sendNotificationWithType(
						"you have becomed an organizer in " + entity.entityName
								+ "in " + organization.name, receivers,
						"Entity", entity.id);
				message = "You have succesfuly added " + user.name
						+ " to entity " + entity.entityName
						+ " in organization " + organization.name;

			} else {
				if (permissionOrg.aUserType.equals("organizer")
						&& permissionEnt.aUserType.equals("organizer")) {
					message = user.name + " is already an organizer in "
							+ entity.entityName;
				}
			}
		} else {
			Permission permissionInOrg = new Permission("organizer",
					organization, user, null);
			permissionInOrg.save();
			Permission permissionInEntity = new Permission("organizer",
					organization, user, entity);
			permissionInEntity.save();
			ArrayList<User> receivers = new ArrayList<User>();
			receivers.add(user);
			admin.sendNotificationWithType("you have becomed an organizer in "
					+ entity.entityName + "in " + organization.name, receivers,
					"Entity", entity.id);
			entity.entityOrganizers.add(user);
			entity.save();
			organization.orgMembers.add(user);
			organization.save();
			user.organization.add(organization);
			user.entity.add(entity);
			user.save();
			System.out.println("organizer is assigned");

			message = "You have succesfuly added " + user.name + " to entity "
					+ entity.entityName + " in organization "
					+ organization.name;
		}

		render(message);
	}

	/**
	 * forgotPassword method takes the email of the user and check if he is in
	 * the community and randomly change his password and send the new password
	 * to the user by email.
	 * 
	 * @param myMail
	 *            The user email(user.email) that he forgot its password.
	 * @throws EmailException
	 * @author Nourhan El Sawa
	 */
	public static void forgotPassword(String myMail) throws EmailException {

		List<User> list = User.getUsers();
		list = User.find("email", myMail).fetch(1);
		if (list.size() == 1) {

			User user = User.find("byEmail", myMail).first();
			Random random = new Random();
			user.password = Long.toString(Math.abs(random.nextLong()), 36);
			user.save();
			String messagePrint = "Your new Password is " + user.password;
			Email mail = new Email(user.email, myMail, "Password changed",
					"Your new Password is " + user.password);
			mail.sendEmail();
			String message = mail.message + " " + myMail;
			System.out.println(mail.message + " " + myMail);
			System.out.println(messagePrint);
			forgotPasswordPage();

		} else {

			Email mail = new Email("admin@admin.com", myMail,
					"Not user in community",
					"you can register and become a user in a community");
			mail.sendEmail();
			String message = "no valid mail  " + myMail;
			System.out.println("no valid mail  " + myMail);
			String messagePrint = "you can register and become a user in a community";
			System.out.println(messagePrint);
			forgotPasswordPage();
		}

	}

	/**
	 * Shows all organizations of the site to the admin to be able to choose any
	 * of them and it takes the user id(user) that he wishes to assign him as a
	 * lead.
	 * 
	 * @param userId
	 *            The user the admin wishes to assign him as an organization
	 *            lead.
	 * @author Nourhan El Sawa
	 */
	public static void assignUser(long userId) {
		List organizations = Organization.find("order by email desc").fetch();
		User user = User.findById(userId);
		System.out.println(userId);
		render(userId, user, organizations);

	}

	/**
	 * Shows all Entities of a chosen organization to the admin to be able to
	 * choose any of them and it takes the user id(user) that he wishes to
	 * assign him as an organizer.
	 * 
	 * @param userId
	 *            The user the admin wishes to assign him as an organizer.
	 * @param organizationId
	 *            The organization the admin wishes to assign user to it.
	 * @author Nourhan El Sawa
	 */
	public static void showEntity(long userId, long organizationId) {
		Organization organization = Organization.findById(organizationId);
		List<Entities> entities = organization.allEntities;
		User user = User.findById(userId);
		render(entities, user, organization);
	}

	public static void forgotPasswordPage() {
		render();
	}
}
